using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;

namespace Sandia.MVCFramework.Common
{
    /// <summary>
    /// A custom IComparere for FileInfos. This compares across a number of
    /// attributes, including filename, creation time, access time, write time,
    /// file version number, and if applicable, assembly version number.
    /// </summary>
    public class FileInfoComparer : IComparer<FileInfo>
    {
        #region IComparer<FileInfo> Members

        /// <summary>
        /// Compares the provided FileInfos.
        /// </summary>
        /// <param name="x">A FileInfo to compare.</param>
        /// <param name="y">A FileInfo to compare.</param>
        /// <returns>
        /// Less than 0, x is less than y. Greater than 0, x is greater than y.
        /// 0, they are equal.
        /// </returns>
        public int Compare(
            FileInfo x, 
            FileInfo y)
        {
            FileVersionInfo xVersionInfo = 
                FileVersionInfo.GetVersionInfo(x.FullName);
            FileVersionInfo yVersionInfo = 
                FileVersionInfo.GetVersionInfo(y.FullName);

            // Compare the files across a number of dimensions.
            int fileNameResult = 
                String.Compare(x.Name, y.Name);
            int creationTimeResult = DateTime.Compare(x.CreationTime, y.CreationTime);
            int majorPartResult =
                xVersionInfo.FileMajorPart - yVersionInfo.FileMajorPart;
            int minorPartResult =
                xVersionInfo.FileMinorPart - yVersionInfo.FileMinorPart;
            int buildPartResult =
                xVersionInfo.FileBuildPart - yVersionInfo.FileBuildPart;

            // If the filenames are different.
            if (fileNameResult != 0)
            {
                return fileNameResult;
            }
            // Else if the creation times are different.
            else if (creationTimeResult != 0)
            {
                return creationTimeResult;
            }
            // Else if the version major part is different.
            else if (majorPartResult != 0)
            {
                return majorPartResult;
            }
            // Else if the version minor part is different.
            else if (minorPartResult != 0)
            {
                return minorPartResult;
            }
            // Else if the version build part is different.
            else if (buildPartResult != 0)
            {
                return buildPartResult;
            }

            // If the file is an assembly, we need to compare the assembly version.
            if (x.Extension.Equals(".dll", StringComparison.CurrentCultureIgnoreCase))
            {
                try
                {
                    // Get the assembly meta data.
                    AssemblyName xAssemblyName =
                        AssemblyName.GetAssemblyName(x.FullName);
                    AssemblyName yAssemblyName =
                        AssemblyName.GetAssemblyName(y.FullName);

                    // Compare the version numbers.
                    majorPartResult =
                        xAssemblyName.Version.Major - yAssemblyName.Version.Major;
                    minorPartResult =
                         xAssemblyName.Version.Minor - yAssemblyName.Version.Minor;
                    buildPartResult =
                         xAssemblyName.Version.Build - yAssemblyName.Version.Build;

                    // If the version major part is different.
                    if (majorPartResult != 0)
                    {
                        return majorPartResult;
                    }
                    // Else if the version minor part is different.
                    else if (minorPartResult != 0)
                    {
                        return minorPartResult;
                    }
                    // Else if the version build part is different.
                    else if (buildPartResult != 0)
                    {
                        return buildPartResult;
                    }
                }
                catch (Exception e)
                {
                    Console.Out.Write(e.Message);
                }
            }

            // No differences found, the files are equal.
            return 0;
        }

        #endregion
    }
}
